package com.sun.javafx.fxml;

import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;

import java.lang.ref.WeakReference;
import java.util.*;
import java.util.function.Function;

public class FXMLObservables {

    /**
     * 可观测列表(软)绑定
     * @param src 可观察列表
     * @param target 目标列表
     * @param fun 目标对象生成器
     */
    public static <S,T> void weakBind(ObservableList<S> src, List<T> target, Function<S,T> fun){
        Platform.runLater(() -> target.clear());
        for (int i = 0; i < src.size(); i++) {
            int index = i;
            T apply = fun.apply(src.get(i));
            Platform.runLater(() -> target.add(index,apply));
        }

        //软绑定,不需要显式解除绑定
        WeakReference<List<T>> ref = new WeakReference<>(target);
        src.addListener(new ListChangeListener<S>() {
            @Override
            public void onChanged(Change<? extends S> c) {
                List<T> weakTarget = ref.get();
                if(weakTarget == null){
                    src.removeListener(this);
                }else {
                    while (c.next()) {
                        int from = c.getFrom();
                        int to = c.getTo();

                        if (c.wasReplaced()) {
                            List<? extends S> list = c.getAddedSubList();
                            for (int i = 0; i < list.size(); i++) {
                                T apply = fun.apply(list.get(i));
                                int index = from + i;
                                Platform.runLater(() -> weakTarget.set(index, apply));
                            }
                        } else {
                            if (c.wasAdded()) {
                                List<? extends S> list = c.getAddedSubList();
                                for (int i = 0; i < list.size(); i++) {
                                    T apply = fun.apply(list.get(i));
                                    int index = from + i;
                                    Platform.runLater(() -> weakTarget.add(index, apply));
                                }
                            }

                            if (c.wasRemoved()) {
                                Platform.runLater(() -> {
                                    for (int i = from; i >= to; i--) {
                                        weakTarget.remove(i);
                                    }
                                });
                            }
                        }

                        if (c.wasUpdated()) {
                            throw new RuntimeException("vue4j 不支持ObservableList的updated事件");
                        }

                        if (c.wasPermutated()) {
                            throw new RuntimeException("vue4j 不支持ObservableList的Permutated事件");
                        }
                    }
                }
            }
        });
    }

}
